「委派型別」代表對方法的參考,其中含有特定參數清單與傳回型別。
委派讓您可將方法視為實體,而實體能指派給變數或當作參數來傳遞。
委派就類似其他程式設計語言中的函式指標,但與函式指標的不同之處是,委派是物件導向且為型別安全。
簡單來說 Delegate (委派)是將 function 當成參數傳遞的型別。
委派的方式有三種具名函式、匿名函式、Lambda運算式。
具名函式: 將已宣告的方法(nameMethod
)指給委派
匿名函式: delegate (arguments) { statements }
delegate: 匿名函式的的保留字
arguments: 傳入參數的宣告,可以多個參數(以,
隔開)
statements: 此函式執行的程式碼片段
Lambda: arguments => expression | block
arguments: 傳入參數的宣告,可以多個參數(以,隔開)。
只有一個參數時可以不用括號,多個參數時都要加上括號
可以不用明確指定型別
可以明確指定型別
明確指定型別時一定要加上括號
沒有傳入參數時用空括號 ()
表示
expression: 運算式,不括大括號 {}
,只能單行程式碼,代表回傳值
block: { statements }
: 程式碼區塊,statement
為此函式執行的程式碼片段
委派需要事先宣告此委派類型的傳入參數與傳回值,至少 0 個參數,至多 32 個參數,可以無傳回值,也可以指定傳回值類型。
注意 參數與傳回型別需一致
static void Main (string[] args) {
MyDelegate d;
d = new MyDelegate (add);
var v = d (1, 2); // 1 + 2 = 3
Console.WriteLine (v);
d = new MyDelegate (subtract);
v = d (2, 1); // 2 - 1 = 1
Console.WriteLine (v);
}
public delegate int MyDelegate (int x, int y);
public static int add (int a, int b) {
return a + b;
}
public static int subtract (int a, int b) {
return a - b;
}
使用匿名方法可以減少在具現化委派中撰寫程式碼的額外負荷,因為不必另外建立一個方法。
static void Main (string[] args) {
MyDelegate d;
d = delegate (int x, int y) {
return x + y;
};
var v = d (1, 2); // 1 + 2 = 3
Console.WriteLine (v);
d = delegate (int x, int y) {
return x - y;
};
v = d (2, 1); // 2 - 1 = 1
Console.WriteLine (v);
}
public delegate int MyDelegate (int x, int y);
以 lambda 運算式取代匿名方法,成為撰寫程式碼內嵌的慣用方式。
static void Main (string[] args) {
MyDelegate d;
d = (int x, int y) => { return x + y; };
var v = d (1, 2); // 1 + 2 = 3
Console.WriteLine (v);
d = (x, y) => x - y;
v = d (2, 1); // 2 - 1 = 1
Console.WriteLine (v);
}
public delegate int MyDelegate (int x, int y);
可以看到在減法方法中,lambda 甚至可以省去傳入參數的型別與 return 關鍵字。
除了 Delegate 也可以使用 Action, Func, Predicate 這些類型來進行委派,不用事先宣告委派的類型。
Action是無傳回值的泛型委派。
Action至少0個參數,至多16個參數。
static void Main (string[] args) {
Action<string> action = action1;
action ("123"); // 123
action = action2;
action ("Mio"); // Hi Mio
}
public static void action1 (string a) {
Console.WriteLine (a);
}
public static void action2 (string a) {
Console.WriteLine ("Hi " + a);
}
Func 是有傳回值的泛型委派。
Func 至少0個參數,至多16個參數,以及一個傳回值的型別參數。方法必須有傳回值,不可為 void。
Func<int> 無輸入的參數,且傳回值為 int 型別的委派。
Func<object,string,int> 表示傳入參數為 object , string 傳回值為 int 型別的委派。
static void Main (string[] args) {
Func<int> func = func1;
Console.WriteLine (func ()); // 0
}
public static int func1 () {
return 0;
}
使用 Func 委派時,也能用 Lambda 進行。
static void Main (string[] args) {
Func<int> func = () => 0;
Console.WriteLine (func ()); // 0
Func<int, int, string> func2 = (a, b) => (a + b).ToString ();
Console.WriteLine (func2 (1, 2)); // 1 + 2 = 3
}
Predicate 是返回 bool 型的泛型委派。
Predicate<int> 表示傳入參數為 int 返回 bool 的委派。
Predicate 有且只有一個參數,傳回值固定為 bool。
static void Main (string[] args) {
Predicate<int> predicate = predicate1;
Console.WriteLine (predicate (0)); // True
}
public static bool predicate1 (int a) {
return a == 0;
}
這邊在多補充點有關 Lambda 的觀念,因為 Lambda 在目前的程式碼撰寫很容易會使用到。
Lambda 運算式是匿名函式,可用來建立委派或運算式樹狀架構類型。
使用 Lambda 運算式可以撰寫區域函式,這些函式可以當做引數傳遞,或是當做函式呼叫的值傳回。
Lambda 運算式對於撰寫 LINQ 查詢運算式而言特別有用。
題外話:LINQ 會在之後做介紹。
建立 Lambda 運算式,需在 Lambda 運算子(=>) 的左邊指定輸入參數 (如果有的話),並將運算式或陳述式區塊放在另一邊。
結構如:arguments => expression | block
(=>) 運算子與指派 (=) 具有相同的優先順序。
()
//Only one input parameter
x => x * x //legal
(x) => x * x //legal
//Two or more input parameters
x, y => x * y //illegal
(x, y) => x * y //legal
()
,不明確指定型別也可以string x => x * x //illegal
(string x) => x * x //legal
x => x * x
()
表示() => Console.WriteLine("Hello Lambda")
expression
,可以不用 {}
包住程式,程式行的最後也不用加 ;
,其程式碼所代表的是回傳值x => x * x //delegate (int x) { return x * x; }
expression
格式的Lambda稱為Lambda運算式(Lambda Expressions);
x => { return x * x; }
block
格式的Lambda稱為Lambda陳述式(Lambda Statements)今天介紹了委派,其實有點算是講古吧,但如果沒有基本觀念的話,直接使用也容易搞不懂在用什麼。上面也講過了,現在主流都是用 Lambda 了,尤其是操作 LINQ 時,幾乎每一句都是,所以 Lamda 是什麼,這邊也先告訴你了。
Lambda 也可以在宣告方法時使用如
static int add2num (int a, int b) => a + b;
所以與其說是教委派,更多的是 Lambda 的使用,但如果沒有委派的觀念,使用起 Lambda 時總會卡手卡腳的。
本來今天是想介紹泛型的,打到一半覺得還是先講委派好了,泛型後面接集合比較順,也可以不用再看一次類別。
感謝閱讀。
參考連結
C# 委派 - C# 語言教學課程 | Microsoft Docs
匿名方法 (C# 程式設計手冊) | Microsoft Docs
Lambda 運算式 (C# 程式設計手冊) | Microsoft Docs
C#委託的介紹(delegate、Action、Func、predicate) @ 資訊園 :: 痞客邦 ::